package com.rose.doorto.footbathdoor.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rose.doorto.common.constant.AuthServerConstant;
import com.rose.doorto.common.constant.Constant;
import com.rose.doorto.footbathdoor.config.AlipayTemplate;
import com.rose.doorto.footbathdoor.enums.MessageStatusEnum;
import com.rose.doorto.footbathdoor.enums.OrderMqConstant;
import com.rose.doorto.footbathdoor.enums.OrderStatusEnum;
import com.rose.doorto.footbathdoor.enums.PayType;
import com.rose.doorto.footbathdoor.fegin.AliPayRemoteFeginService;
import com.rose.doorto.footbathdoor.interceptor.LoginInterceptor;
import com.rose.doorto.footbathdoor.mapper.*;
import com.rose.doorto.footbathdoor.pojo.*;
import com.rose.doorto.footbathdoor.service.OrderService;
import com.rose.doorto.footbathdoor.service.PaymentInfoService;
import com.rose.doorto.footbathdoor.util.PageUtils;
import com.rose.doorto.footbathdoor.util.Query;
import com.rose.doorto.footbathdoor.vo.AlipayNotifyVO;
import com.rose.doorto.footbathdoor.vo.OrderCreateVO;
import com.rose.doorto.footbathdoor.vo.OrderSubmitVO;
import com.rose.doorto.footbathdoor.vo.OrderVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

import static net.sf.jsqlparser.util.validation.metadata.NamedObject.user;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author liqingchao
 * @since 2024-07-23
 */
@Slf4j
@Service
@Transactional
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private TeacherMapper teacherMapper;

    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private AddressMapper addressMapper;

    @Resource
    private AliPayRemoteFeginService payRemoteFeginService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    AlipayTemplate alipayTemplate;

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    QueueMessagesMapper queueMessagesMapper;

    private final ReentrantLock lock = new ReentrantLock();

    /**
     * 获取登录用户的所有订单
     * @return
     */
    @Override
    public List<Order> findAllByUserId(String userId) {
        return orderMapper.findAllByUserId(userId);
    }


    /**
     * 创建订单
     * @param order
     * @return
     */
    @Override
    public int addOrders(Order order) {
        String uuid = UUID.randomUUID().toString();
        order.setOrderSn(uuid);

        return orderMapper.addOrders(order);
    }

    /**
     * 创建订单
     * @param orderVo
     * @return
     */
    @Override
    public int submit(OrderVo orderVo, HttpSession session,String serviceTime) {
        Order order = new Order();
        //获取当前用户信息
        User attribute = (User) session.getAttribute(AuthServerConstant.LOGIN_USER_KEY);
        if (attribute!=null){
            Address address = addressMapper.getDefauleAddressByUserId(attribute.getId());
            order.setUsername(attribute.getUsername());   //下单人名称
            order.setPhone(attribute.getMobile());    //下单人手机号
            order.setAddress(address.getAddressDetails());  //收货地址
        }
        UUID uuid = UUID.randomUUID();
        order.setOrderSn(String.valueOf(uuid));   //订单号
        Project project = projectMapper.getProjectById(Math.toIntExact(orderVo.getPid()));
        if (project!=null){
            order.setProjectimage(project.getImage());   //项目图片
            order.setProjectName(project.getName());  //项目名称
        }
        Teacher teacher = teacherMapper.selectById(orderVo.getTid());
        if (teacher!=null){
            order.setTeacherName(teacher.getName());  //服务人员
        }
//        order.setCreateTime(String.valueOf(new Date())); //订单创建时间
        order.setTaxiPrice(orderVo.getTaxiPrice());      //打车费
        order.setRemarks(orderVo.getRework());           //备注
        order.setRewardPrice(orderVo.getRewardPrice());  //打赏金额
        order.setAppointmentTime(serviceTime);   //服务时间
        //TODO 支付总额 = 打赏金额 + 路费 + 项目金额 + 优惠   后期改动,目前就先这样,先写死
        order.setStatus(OrderStatusEnum.CREATE_NEW.getCode());  //订单状态,代付款
        orderMapper.addOrders(order);
        String orderSn = order.getOrderSn();
        return 1;  //TODO  返回值先写死
    }

    /**
     * 提交订单,创建订单
     * @param submitVO
     * @return
     */
    @Override
    public OrderCreateVO submit(OrderSubmitVO submitVO,String serviceTime,HttpSession session) {
        //TODO 1.验证令牌,后期做
        //TODO 2.构建订单
        OrderCreateVO createVO = new OrderCreateVO();
        Order order = buildOrder(submitVO,serviceTime,session);
        createVO.setOrder(order);
        //TODO 3.向mq中发送订单创建完成消息
        String uuid = UUID.randomUUID().toString();
        QueueMessages messages = new QueueMessages();
        messages.setExchange(OrderMqConstant.ORDER_DOOR_EVENT_EXCHANGE);
        messages.setRouteKey(OrderMqConstant.ORDER_DOOR_CREATE_ROUTING_KEY);
        messages.setMessageId(uuid.toString());
        messages.setStatus(MessageStatusEnum.RETRYSTATUS.getCode());  //消息状态,0-重试
        messages.setCount(1);                         //重试次数
        String string = JSON.toJSONString(order);
        messages.setContent(string);                  //发送的内容
        //1分钟后重试的时间
        messages.setTryTime(new Date(System.currentTimeMillis()+1000+60+1));
        queueMessagesMapper.insert(messages);
        try {
            rabbitTemplate.convertAndSend(OrderMqConstant.ORDER_DOOR_EVENT_EXCHANGE, OrderMqConstant.ORDER_DOOR_CREATE_ROUTING_KEY, order,new CorrelationData(uuid.toString()));
        }catch (AmqpException e){
            log.warn("向mq发送订单新创建消息失败，自动重试一次");
            rabbitTemplate.convertAndSend(OrderMqConstant.ORDER_DOOR_EVENT_EXCHANGE, OrderMqConstant.ORDER_DOOR_CREATE_ROUTING_KEY, order,new CorrelationData(uuid.toString()));
        }
        return createVO;
    }

    /**
     * 构建订单
     * @param orderSubmitVO
     * @return
     */
//    private Order buildOrder(OrderSubmitVO orderSubmitVO,String serviceTime){
    private Order buildOrder(OrderSubmitVO orderSubmitVO,String serviceTime,HttpSession session){
//        User user = LoginInterceptor.threadLocal.get();
        Order order = new Order();
        User user = (User) session.getAttribute(AuthServerConstant.LOGIN_USER_KEY);
        if (user!=null){
            //1. 下单人
            order.setUserId(user.getId());
            order.setUsername(user.getUsername());
            //2. 下单人手机号
            order.setPhone(user.getMobile());
        }
        Address address = addressMapper.getDefauleAddressByUserId(user.getId());
        //3.下单人收货地址
        order.setAddress(address.getAddressDetails());
        //4.支付方式,支付宝,先写死,目前只做这一种
        order.setPayType(PayType.ALIPAY.getCode());
        Project project = projectMapper.getProjectById(Math.toIntExact(orderSubmitVO.getPid()));
        if (project!=null){
            //5.项目图片
            order.setProjectimage(project.getImage());
            //6.项目名称
            order.setProjectName(project.getName());
        }
        Teacher teacher = teacherMapper.selectById(orderSubmitVO.getTid());
        if (teacher!=null){
            //7.服务人员
            order.setTeacherName(teacher.getName());
        }
        //8.打车费
        order.setTaxiPrice(orderSubmitVO.getTaxiPrice());
        //9.备注
        order.setRemarks(orderSubmitVO.getRework());
        //10.打赏金额
        order.setRewardPrice(orderSubmitVO.getRewardPrice());
        //11.服务时间
        order.setAppointmentTime(serviceTime);
        //12.订单状态,代付款
        order.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        //13.订单号
        String uuid = UUID.randomUUID().toString();
        order.setOrderSn(uuid);
        orderMapper.addOrders(order);
        return order;
    }

    /**
     * 处理订单
     * @param params
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void processOrder(Map<String, String> params) {

        log.info("处理订单");

        //获取订单号
        String orderNo = params.get("out_trade_no");

        /*在对业务数据进行状态检查和处理之前，
        要采用数据锁进行并发控制，
        以避免函数重入造成的数据混乱*/
        //尝试获取锁：
        // 成功获取则立即返回true，获取失败则立即返回false。不必一直等待锁的释放
        if(lock.tryLock()) {
            try {

                //处理重复通知
                //接口调用的幂等性：无论接口被调用多少次，以下业务执行一次
//                String orderStatus = orderInfoService.getOrderStatus(orderNo);
                Order order = orderMapper.getOrderByOrderSn(orderNo);
                Integer orderStatus = order.getStatus();
                if (!OrderStatusEnum.CREATE_NEW.getCode().equals(orderStatus)) {
                    return;
                }

                //更新订单状态
//                orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.SUCCESS);
                updateOrderStatusByOrderSn(orderNo,OrderStatusEnum.PAYED.getCode());

                //记录支付日志
                // 2.保存支付流水
//                PaymentInfoEntity paymentInfo = new PaymentInfoEntity();
//                paymentInfo.setAlipayTradeNo(notifyVO.getTrade_no());
//                paymentInfo.setCallbackTime(notifyVO.getNotify_time());
//                paymentInfo.setOrderSn(notifyVO.getOut_trade_no());
//                paymentInfo.setPaymentStatus(notifyVO.getTrade_status());
//                paymentInfo.setTotalAmount(new BigDecimal(notifyVO.getTotal_amount()));
//                paymentInfo.setSubject(notifyVO.getSubject());
//                paymentInfoService.save(paymentInfo);
                paymentInfoService.createPaymentInfoForAliPay(params);

            } finally {
                //要主动释放锁
                lock.unlock();
            }
        }

    }

    /**
     * 更新订单状态
     * @param orderSn
     * @param status
     * @return
     */
    private boolean updateOrderStatusByOrderSn(String orderSn, Integer status) {
        return orderMapper.updateOrderPayStatus(orderSn,status);
    }
    /**
     * 获取指定状态的订单
     * @param status
     * @return
     */
    @Override
    public List<Order> getOrderByStatus(int status,int userId) {
        return orderMapper.getOrderByStatus(status,userId);

    }

    /**
     * 查看订单详情
     * @param orderSn
     * @return
     */
    @Override
    public Order getOrderByOrderSn(String orderSn) {
        return orderMapper.getOrderByOrderSn(orderSn);
    }

    /**
     * 根据项目查询订单列表(模糊查询)
     * @param projectName
     * @return
     */
    @Override
    public List<Order> findOrderByLikeProject(String projectName,String userId) {
        return orderMapper.findOrderByLikeProject(projectName,userId);
    }

    /**
     * 查询指定时间范围内的订单
     * @param code
     * @return
     */
    @Override
    public List<Order> getOrderByCreatime(int code,int userId) {
        return orderMapper.getOrderByCreatime(code,userId);
    }

    /**
     * 处理支付宝异步通知信息
     * @param notifyVO
     * @param request
     * @return
     */
    @Transactional
    @Override
    public String handleAlipayNotify(AlipayNotifyVO notifyVO, HttpServletRequest request) {
        boolean verified;
        // 1.验签
        try {
            verified = alipayTemplate.signVerify(request);
        } catch (Exception e) {
            log.warn("阿里支付异步通知验签失败");
            return "error";
        }
        // 验签失败
        if (!verified) {
            return "error";
        }
        // 2.保存支付流水
        PaymentInfoEntity paymentInfo = new PaymentInfoEntity();
        paymentInfo.setAlipayTradeNo(notifyVO.getTrade_no());
        paymentInfo.setCallbackTime(notifyVO.getNotify_time());
        paymentInfo.setOrderSn(notifyVO.getOut_trade_no());
        paymentInfo.setPaymentStatus(notifyVO.getTrade_status());
        paymentInfo.setTotalAmount(notifyVO.getTotal_amount());
        paymentInfo.setSubject(notifyVO.getSubject());
        paymentInfoService.save(paymentInfo);
        // 3.修改订单状态为已支付
        if (notifyVO.getTrade_status().equals("TRADE_SUCCESS") || notifyVO.getTrade_status().equals("TRADE_FINISHED")) {
            String orderSn = notifyVO.getOut_trade_no();
            updateOrderStatusByOrderSn(orderSn, OrderStatusEnum.PAYED.getCode());
        }
        return "success";
    }

    /**
     * 分页查询当前登录用户的订单列表
     * @param params
     * @return
     */
    @Override
    public PageUtils getCurrentUserOrderList(Map<String, Object> params,HttpSession session) {
        User user = (User) session.getAttribute(AuthServerConstant.LOGIN_USER_KEY);
        //获取当前登录用户的所有订单
        IPage<Order> page = this.page(new Query<Order>().getPage(params),
                new QueryWrapper<Order>().eq("userId", user.getId()).orderByDesc("id"));
        return new PageUtils(page);
    }

    /**
     * 分页查询所有订单信息
     * @param params
     * @return
     */
    @Override
    public PageUtils getOrderList(Map<String, Object> params) {
        //获取所有的订单信息
        IPage<Order> page = this.page(new Query<Order>().getPage(params),
                new QueryWrapper<Order>().orderByDesc("createTime"));
        return new PageUtils(page);
    }

    /**
     * 修改订单的支付方式
     * @param payType
     * @return
     */
    @Override
    public boolean updateOrderPayType(String orderSn,int payType) {
        return orderMapper.updateOrderPayType(orderSn,payType);
    }

    /**
     * 手机号码隐藏
     * @param phoneNumber
     * @return
     */
    public List<Order> hidePhoneNumber(String phoneNumber){
        List<Order> arrayList = new ArrayList<>();
        if (phoneNumber == null || phoneNumber.length() == 0){
            return arrayList;
        }
        int showLength = 4; //显示的长度,例如最后四位
        String hiddenPhone = phoneNumber.substring(0,3); //前三位保持不变
        for (int i = 3; i < phoneNumber.length() - showLength; i++) {
            hiddenPhone += "*"; // 用星号替换
        }
        hiddenPhone += phoneNumber.substring(phoneNumber.length() - showLength); // 最后四位
        Order order = new Order();
        order.setPhone(hiddenPhone);
        arrayList.add(order);
        return arrayList;

    }

    /**
     * 获取半个小时之后本来8小时的时间 段，每30分钟一段
     * @param
     * @return
     */
    public List<LocalDateTime> getTimeIntervals(){
        LocalDateTime nowTime = LocalDateTime.now();  //当前时间
        Duration halfHour = Duration.ofMinutes(30);
        LocalDateTime minus = nowTime.plus(halfHour);//.minus(halfHour);   //半小时后的时间
        LocalDateTime endTime = minus.plusHours(8); // 假设时间区间是8小时
        List<LocalDateTime> intervals = new ArrayList<>();
        while (minus.isBefore(endTime)) {
            intervals.add(minus);
            minus = minus.plus(halfHour);
        }
        System.out.println("时间段获取"+intervals);
        return intervals;
    }




}
